import os
import subprocess
import logging
import re
from datetime import datetime
from typing import Dict, Any, Optional
import uvicorn
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    handlers=[
        logging.FileHandler("deploy.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("pdf-deploy")

# 创建 FastAPI 应用
app = FastAPI(title="gitee 部署工具")

# 确保 static 目录存在
os.makedirs("static", exist_ok=True)

# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")

# 配置模板引擎
templates = Jinja2Templates(directory="templates")

# 定义请求数据模型
class DeployRequest(BaseModel):
    domain: str
    gitrepo: str
    command: str

# 检查是否安装了必要的依赖
def check_dependencies() -> bool:
    dependencies = ["git", "nginx"]
    missing = []
    
    for dep in dependencies:
        try:
            if dep == "nginx":
                subprocess.run(["nginx", "-v"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
            else:
                subprocess.run([dep, "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
        except FileNotFoundError:
            missing.append(dep)
    
    if missing:
        logger.error(f"缺少以下依赖项: {', '.join(missing)}")
        return False
    return True

# 处理Gitee仓库URL，移除可能的前缀并提取仓库名
def process_gitee_url(repo_url: str) -> Dict[str, str]:
    # 移除URL前缀
    if repo_url.startswith(("https://gitee.com/", "http://gitee.com/")):
        repo_path = re.sub(r'^https?://gitee\.com/', '', repo_url)
    else:
        repo_path = repo_url
    
    # 提取仓库名称 (最后一个斜杠后的部分)
    repo_name = repo_path.split('/')[-1]
    
    return {
        "full_path": repo_path,   # 完整路径 (用户名/仓库名)
        "repo_name": repo_name    # 仅仓库名
    }

# 生成Nginx配置文件
def generate_nginx_config(domain: str, app_port: int = 8080) -> str:
    """根据域名和应用端口生成Nginx配置"""
    nginx_config = f"""server {{
    listen 80;
    server_name {domain};

    location / {{
        proxy_pass http://127.0.0.1:{app_port};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }}
}}
"""
    return nginx_config

# 应用Nginx配置
def apply_nginx_config(domain: str, config_content: str) -> bool:
    """将生成的配置应用到Nginx"""
    try:
        # 创建配置文件
        config_path = f"/etc/nginx/conf.d/{domain}.conf"
        
        with open(config_path, "w") as f:
            f.write(config_content)
        
        # 测试配置是否有效
        result = subprocess.run(
            ["nginx", "-t"],
            capture_output=True,
            text=True,
            check=False
        )
        
        if result.returncode != 0:
            logger.error(f"Nginx配置测试失败: {result.stderr}")
            # 如果配置无效，则删除配置文件
            os.remove(config_path)
            return False
        
        # 重新加载Nginx
        reload_result = subprocess.run(
            ["nginx", "-s", "reload"],
            capture_output=True,
            text=True,
            check=False
        )
        
        if reload_result.returncode != 0:
            logger.error(f"Nginx重载失败: {reload_result.stderr}")
            return False
            
        return True
    except Exception as e:
        logger.error(f"应用Nginx配置时出错: {e}")
        return False

# 主页路由
@app.get("/", response_class=HTMLResponse)
async def read_root():
    try:
        with open("static/pdf.html", "r", encoding="utf-8") as f:
            content = f.read()
        return HTMLResponse(content=content)
    except Exception as e:
        logger.error(f"读取HTML文件失败: {e}")
        raise HTTPException(status_code=500, detail="无法加载页面")

# 部署接口
@app.post("/deploy")
async def deploy(request: DeployRequest) -> Dict[str, Any]:
    logger.info(f"开始部署: {request.dict()}")
    
    # 验证输入
    if not all([request.domain, request.gitrepo, request.command]):
        logger.warning("请求参数不完整")
        return {"success": False, "error": "所有字段都是必填的"}
    
    # 处理Gitee仓库URL
    repo_info = process_gitee_url(request.gitrepo)
    processed_repo = repo_info["full_path"]
    repo_name = repo_info["repo_name"]
    
    # 项目部署到 /projects/{repo_name} 目录
    project_folder = f"/projects/{repo_name}"
    
    # 创建部署脚本
    deploy_script = f"""#!/bin/bash
# 确保 /projects 目录存在
mkdir -p /projects

# 创建或进入项目目录
mkdir -p {project_folder}
cd {project_folder}

# 克隆或更新仓库
if [ -d ".git" ]; then
    git pull
else
    git clone https://gitee.com/{processed_repo} .
fi

# 保存域名配置
echo "域名: {request.domain}" > config.txt

# 执行用户指定的命令
{request.command}
"""
    
    # 尝试生成和应用Nginx配置
    nginx_success = False
    nginx_message = ""
    try:
        # 提取应用端口 (默认为 8080)
        app_port = 8080
        # 注: 这里可以从命令中提取端口，如果命令格式允许的话
        
        # 生成Nginx配置
        nginx_config = generate_nginx_config(request.domain, app_port)
        
        # 应用Nginx配置 (需要root权限)
        nginx_success = apply_nginx_config(request.domain, nginx_config)
        
        if nginx_success:
            nginx_message = f"Nginx配置已成功应用于域名 {request.domain}"
        else:
            nginx_message = "Nginx配置应用失败，可能需要手动配置或需要root权限"
    except Exception as e:
        nginx_success = False
        nginx_message = f"Nginx配置过程出现错误: {str(e)}"
        logger.error(nginx_message)
    
    # 将脚本保存到临时文件
    script_path = "temp_deploy.sh"
    try:
        with open(script_path, "w", encoding="utf-8") as f:
            f.write(deploy_script)
        os.chmod(script_path, 0o755)  # 添加执行权限
        
        # 执行部署脚本
        process = subprocess.Popen(
            ["bash", script_path], 
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        stdout, stderr = process.communicate()
        
        # 记录输出
        output = stdout + (f"\n错误输出:\n{stderr}" if stderr else "")
        if nginx_message:
            output += f"\n\nNginx配置: {nginx_message}"
            
        logger.info(f"部署结果: {process.returncode}")
        if stderr:
            logger.error(f"部署错误输出: {stderr}")
        
        # 删除临时脚本
        if os.path.exists(script_path):
            os.remove(script_path)
        
        # 判断部署结果
        if process.returncode == 0:
            logger.info("部署成功")
            return {
                "success": True, 
                "output": output,
                "nginx_success": nginx_success,
                "nginx_message": nginx_message,
                "project_path": project_folder
            }
        else:
            logger.error(f"部署失败，退出码: {process.returncode}")
            return {
                "success": False, 
                "error": f"部署命令失败，退出码: {process.returncode}", 
                "output": output,
                "nginx_success": nginx_success,
                "nginx_message": nginx_message
            }
            
    except Exception as e:
        logger.exception(f"部署过程异常: {e}")
        # 清理临时文件
        if os.path.exists(script_path):
            os.remove(script_path)
        return {"success": False, "error": str(e)}

# 健康检查接口
@app.get("/health")
async def health_check():
    return {"status": "ok", "timestamp": datetime.now().isoformat()}

# 入口点
if __name__ == "__main__":
    if not check_dependencies():
        logger.error("缺少必要的依赖项，请安装后再运行")
        print("错误: 缺少必要的依赖项。请安装git和nginx后再运行。")
        print("可以运行以下命令安装所需依赖:")
        print("sudo apt update && sudo apt install -y git nginx")
        exit(1)
        
    logger.info("gitee 部署工具启动")
    # 启动FastAPI服务器
    uvicorn.run(app, host="0.0.0.0", port=3000) 